package puzzle.slilin2.data;

import puzzle.common.point.Pnt;
import puzzle.common.point.PntHelper;
import tomoto.assertion.ParamUtil;
import tomoto.util.ArrayUtil;

/**
 * Pnt操作の補助関数群。
 * 
 * @author tomoto
 */
public class SlilinPntHelper {
	/**
	 * 論理的なセルの座標をデータ上のセルの座標に変換する。
	 * 
	 * @param p 論理的なセルの座標。
	 * @return データ上のセルの座標。常に数値セル。
	 */
	public static Pnt getPhysicalPoint(Pnt p) {
		return new Pnt(p.x * 2 + 2, p.y * 2 + 2);
	}

	/**
	 * 数値セルの周辺(4方)の線セルの位置を返す。
	 * 
	 * @param b 盤面
	 * @param p 数値セル
	 * 
	 * @return p周辺の線セルの位置の配列。
	 */
	public static Pnt[] getLinePointsAroundNumber(SlilinBoard b, Pnt p) {
		ParamUtil.check(getCellType(p) == CellType.NUMBER);
		return PntHelper.getDirectNeighborPointsAround(p.x, p.y, b.width, b.height);
	}

	/**
	 * 点セルの周辺(4方)の線セルの位置を返す。
	 * 
	 * @param b 盤面
	 * @param p 点セル
	 * 
	 * @return p周辺の線セルの位置の配列。北から時計回り。
	 */
	public static Pnt[] getLinePointsAroundDot(SlilinBoard b, Pnt p) {
		ParamUtil.check(getCellType(p) == CellType.DOT);
		return PntHelper.getDirectNeighborPointsAround(p.x, p.y, b.width, b.height);
	}

	/**
	 * 数値セルの周辺(4隅方)の点セルの位置を返す。
	 * 
	 * @param b 盤面
	 * @param p 数値セル
	 * 
	 * @return p周辺の点セルの位置の配列。北西から時計回り。
	 */
	public static Pnt[] getDotPointsAroundNumber(SlilinBoard b, Pnt p) {
		Pnt[] ps = new Pnt[4];
		int i = 0;

		if (p.x < b.width - 1) {
			if (p.y >= 1) ps[i++] = new Pnt(p.x + 1, p.y - 1);
			if (p.y < b.height - 1) ps[i++] = new Pnt(p.x + 1, p.y + 1);
		}
		if (p.x >= 1) {
			if (p.y < b.height - 1) ps[i++] = new Pnt(p.x - 1, p.y + 1);
			if (p.y >= 1) ps[i++] = new Pnt(p.x - 1, p.y - 1);
		}

		return i == 4 ? ps : ArrayUtil.dup(ps, i);
	}

	private static CellType[] CELL_TYPE_MAP = { CellType.NUMBER, CellType.VLINE, CellType.HLINE,
			CellType.DOT };

	/**
	 * セル種別を返す。
	 * 
	 * @param p セル
	 * @return セル種別
	 */
	public static CellType getCellType(Pnt p) {
		return getCellType(p.x, p.y);
	}

	public static CellType getCellType(int x, int y) {
		int code = (x & 1) + (y & 1) * 2;
		return CELL_TYPE_MAP[code];
	}

	/**
	 * セル種別が線(縦線または横線)であればtrue。
	 * 
	 * @param p セル
	 * @return セル種別が線であればtrue。
	 */
	public static boolean isCellTypeLine(Pnt p) {
		return isCellTypeLine(p.x, p.y);
	}

	public static boolean isCellTypeLine(int x, int y) {
		return (getCellType(x, y) == CellType.HLINE || getCellType(x, y) == CellType.VLINE);
	}

}
